#Author: didiplus
#Date: 2025-01-22 15:34:24
#LastEditTime: 2025-01-22 15:34:27
#LastEditors: didiplus
#Description: 验证码的基类
#FilePath: \pythonscript\Captcha\utls\CaptchaBase.py
import base64
import io
import os
import random
from PIL import Image, ImageDraw, ImageFont
from .CaptchaWithBezier import CaptchaWithBezier

class CaptchaBase:
    """验证码基类"""

    # 常用颜色 (RGB 格式)
    COLORS = [
        (0, 135, 255), (51, 153, 51), (255, 102, 102),
        (255, 153, 0), (153, 102, 0), (153, 102, 153),
        (51, 153, 153), (102, 102, 255), (0, 102, 204),
        (204, 51, 51), (0, 153, 204), (0, 51, 102)
    ]

    # 验证码文本类型
    TYPE_DEFAULT = 1  # 字母数字混合
    TYPE_ONLY_NUMBER = 2  # 纯数字
    TYPE_ONLY_CHAR = 3  # 纯字母

    # 内置字体
    FONT_NAMES = [
        "actionj.ttf", "epilog.ttf", "fresnel.ttf", "headache.ttf",
        "lexo.ttf", "prefix.ttf", "progbot.ttf", "ransom.ttf",
        "robot.ttf", "scandal.ttf"
    ]

    def __init__(self, length=5, width=150, height=50, char_type=TYPE_DEFAULT):
        self.length = length
        self.width = width
        self.height = height
        self.char_type = char_type
        self.font = None
        self.chars = None

    def set_font(self, font_index=0, size=36):
        """设置字体"""
        font_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "font")
        if not os.path.exists(font_dir):
            raise FileNotFoundError(f"Font directory not found: {font_dir}")

        try:
            font_name = self.FONT_NAMES[font_index]
            font_path = os.path.join(font_dir, font_name)
            self.font = ImageFont.truetype(font_path, size)
        except IndexError:
            raise ValueError(f"Font index out of range. Valid range: 0-{len(self.FONT_NAMES) - 1}")
        except FileNotFoundError:
            raise FileNotFoundError(f"Font file not found: {font_path}")
        except Exception as e:
            raise RuntimeError(f"Failed to set font: {e}")

    def random_color(self):
        """随机获取一种颜色"""
        return random.choice(self.COLORS)
    

    def generate(self):
        """生成验证码，子类需实现"""
        raise NotImplementedError("This method should be implemented by subclasses.")
    
    #
    def draw_bezier_curve(self, draw, num_curves=2):
        """随机画贝塞尔曲线"""
        CaptchaWithBezier(self.width, self.height).draw_bezier_curve(draw, num_curves,self.random_color())
    

    def draw_hollow_circle(self, draw, num_circles=10, min_radius=2, max_radius=5):
        """在图像上绘制多个空心圆"""
        for _ in range(num_circles):
            x = random.randint(0, self.width - 1)
            y = random.randint(0, self.height - 1)
            radius = random.randint(min_radius, max_radius)
            
            # 检查圆心坐标和半径是否在画布范围内
            x = max(0, min(x, self.width - 1))
            y = max(0, min(y, self.height - 1))
            radius = min(radius, min(x, self.width - x - 1), min(y, self.height - y - 1))
            
            color = self.random_color()
            draw.ellipse([(x - radius, y - radius), (x + radius, y + radius)], outline=color, width=2)


    def to_base64(self, image: Image.Image, format="PNG") -> str:
        """将验证码图像转换为 Base64 编码"""
        buffer = io.BytesIO()
        image.save(buffer, format=format)
        buffer.seek(0)
        base64_data = base64.b64encode(buffer.read()).decode("utf-8")
        return f"data:image/{format.lower()};base64,{base64_data}"
    
    def save_image(self, image: Image.Image, filename: str):
        """保存验证码图像为 PNG 文件"""
        image.save(filename, format="PNG")

    def get_text(self) -> str:
        """获取验证码文本"""
        if self.chars is None:
            self.generate()
        return self.chars